package com.megalith.controller;

import cn.hutool.core.bean.BeanUtil;
import com.megalith.entity.DistanceQuery;
import com.megalith.entity.PositionInfo;
import com.megalith.entity.UserInfo;
import com.megalith.vo.UserQueryResultVO;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.geo.*;
import org.springframework.data.redis.connection.RedisGeoCommands;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;

/**
 * @Description TODO
 * @Author lfp
 * @Date 2021/9/27 22:14
 * @Version 1.0
 */
@RestController
@RequestMapping("/geo")
@Slf4j
@Api(value = "redis geo",tags = "redis")
public class RedisGeoController {
    private final String GEO_KEY = "geo:locations";
    private final String USER_LIST_KEY = "geo:users";

    @Autowired
    private RedisTemplate redisTemplate;

    @ApiOperation("上报位置")
    @PostMapping("add")
    public Long addGeo(@RequestBody PositionInfo positionInfo){
        log.info("=====》开始保存信息，用户姓名：{}",positionInfo.getUserName());
        //保存基本信息
        redisTemplate.opsForSet().add(USER_LIST_KEY,BeanUtil.copyProperties(positionInfo,UserInfo.class));
        Set<UserInfo> members = redisTemplate.opsForSet().members(USER_LIST_KEY);
        log.info("=====》最新保存后的内容为：{}",members);


        //保存地理信息
        return redisTemplate.opsForGeo().add(GEO_KEY, positionInfo.getPosition(), positionInfo.getUserId());
    }

    @ApiOperation("离线")
    @PostMapping("offline")
    public Long offline(@RequestBody UserInfo userInfo){
        log.info("=====》将要移除：{}",userInfo);
        Long remove = redisTemplate.opsForSet().remove(USER_LIST_KEY, userInfo);

        Set<UserInfo> members = redisTemplate.opsForSet().members(USER_LIST_KEY);
        log.info("=====》最新内容为：{}",members);

        return remove;
    }

    @ApiOperation("根据距离获取范围内的原始要素")
    @PostMapping("calculate")
    public GeoResults calculate(@RequestBody DistanceQuery query){
        //距离（单位为km）
        Distance distance = new Distance(query.getDistance(), Metrics.KILOMETERS);
        //根据传入的坐标和半径距离，生成查询的地理空间范围
        Circle circle = new Circle(query.getPosition(),distance);

        //构造半径查询条件
        RedisGeoCommands.GeoRadiusCommandArgs args = RedisGeoCommands.GeoRadiusCommandArgs
                .newGeoRadiusArgs()
                .includeDistance()
                .includeCoordinates()
                .sortAscending()
                //.limit(5) //返回结果条数限制
                ;

        GeoResults radius = redisTemplate.opsForGeo().radius(GEO_KEY, circle, args);
        return radius;
    }


    @ApiOperation("根据距离获取范围内的筛选要素")
    @PostMapping("calculate/filter")
    public List<UserQueryResultVO> calculateAndFilter(@RequestBody DistanceQuery query){
        //距离（单位为km）
        Distance distance = new Distance(query.getDistance(), Metrics.MILES);
        //根据传入的坐标和半径距离，生成查询的地理空间范围
        Circle circle = new Circle(query.getPosition(),distance);

        //构造半径查询条件
        RedisGeoCommands.GeoRadiusCommandArgs args = RedisGeoCommands.GeoRadiusCommandArgs
                .newGeoRadiusArgs()
                .includeDistance()
                .includeCoordinates()
                .sortAscending()
                //.limit(5) //返回结果条数限制
                ;
        //范围内的坐标
        GeoResults radius = redisTemplate.opsForGeo().radius(GEO_KEY, circle, args);

        //符合条件记录
        List<GeoResult> geoResultList = radius.getContent();
        log.info("====>geoResultList数据：{}",geoResultList);

        //当前在线用户集合
        Set<UserInfo> members = redisTemplate.opsForSet().members(USER_LIST_KEY);

        List<UserQueryResultVO> resultVOS = new ArrayList<>();

        //筛选数据
        geoResultList.forEach(geoResult->{
            RedisGeoCommands.GeoLocation geoLocation = (RedisGeoCommands.GeoLocation) geoResult.getContent();

            members.forEach(userInfo->{
                if (geoLocation.getName().equals(userInfo.getUserId())) {
                    log.info("用户编号：{}的用户：{}，匹配到的坐标数据：{}",userInfo.getUserId(),userInfo.getUserName(),geoResult);
                    UserQueryResultVO userQueryResultVO = new UserQueryResultVO()
                            .setUserInfo(userInfo)
                            .setGeoContent(geoResult);
                    resultVOS.add(userQueryResultVO);
                }
            });
        });
        return resultVOS;
    }
}
